package com.tencent.cloud.iov.kernel.service;

import android.net.Uri;

import com.tencent.cloud.iov.kernel.constant.StatusCode;
import com.tencent.cloud.iov.kernel.model.BaseResponse;
import com.tencent.cloud.iov.kernel.tmpkey.TmpKeyInfo;
import com.tencent.cloud.iov.kernel.tmpkey.TmpKeyRepository;
import com.tencent.cloud.iov.kernel.tmpkey.TmpKeyRequest;
import com.tencent.cloud.iov.util.rx.SimpleObserver;
import com.tencent.mars.xlog.Log;
import com.tencent.qcloud.core.auth.QCloudCredentialProvider;
import com.tencent.qcloud.core.auth.QCloudCredentials;
import com.tencent.qcloud.core.auth.SessionQCloudCredentials;
import com.tencent.qcloud.core.common.QCloudClientException;
import com.tencent.tac.TACApplication;
import com.tencent.tac.storage.StorageResultListener;
import com.tencent.tac.storage.TACStorageOptions;
import com.tencent.tac.storage.TACStorageReference;
import com.tencent.tac.storage.TACStorageService;
import com.tencent.tac.storage.TACStorageTaskSnapshot;
import com.tencent.tac.storage.TACStorageUploadTask;

import java.io.File;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

/**
 * 移动存储服务
 *
 * @author vinsonhuang
 * @date 2018/4/27
 */
public class TXStorageService {

    private static final String TAG = TXStorageService.class.getSimpleName();

    private static final String SERVICE_NAME = "storage";

    private static TXStorageService sInstance = new TXStorageService();

    private TACStorageOptions mTACStorageOptions;

    private MyCredentialProvider mMyCredentialProvider;

    private TXStorageService() {
        mTACStorageOptions = TACApplication.options().sub(SERVICE_NAME);
        mMyCredentialProvider = new MyCredentialProvider();
        mTACStorageOptions.setCredentialProvider(mMyCredentialProvider);
    }

    /**
     * 获取移动存储服务实例
     *
     * @return 移动存储服务实例
     */
    public static TXStorageService getInstance() {
        return sInstance;
    }

    /**
     * 上传文件（字节数组）
     *
     * @param fileType 文件类型
     * @param fileHash 文件sha256
     * @param data     文件字节数组
     * @param listener 上传监听器
     */
    public void uploadData(int fileType, String fileHash, final byte[] data,
                           final StorageResultListener<TACStorageTaskSnapshot> listener) {
        getStorageInitInfo(fileType, fileHash, data, null, listener);
    }

    /**
     * 上传文件
     *
     * @param fileType 文件类型
     * @param fileHash 文件sha256
     * @param filePath 文件路径
     * @param listener 上传监听器
     */
    public void uploadFile(int fileType, String fileHash, final String filePath,
                           final StorageResultListener<TACStorageTaskSnapshot> listener) {
        getStorageInitInfo(fileType, fileHash, null, filePath, listener);
    }

    private void getStorageInitInfo(int fileType, String fileHash,
                                    final byte[] data, final String filePath,
                                    final StorageResultListener<TACStorageTaskSnapshot> listener) {
        TmpKeyRequest request = new TmpKeyRequest(fileType, fileHash);
        TmpKeyRepository.getInstance().getProfileTmpKey(request)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new SimpleObserver<BaseResponse<TmpKeyInfo>>() {
                    @Override
                    public void onNext(BaseResponse<TmpKeyInfo> response) {
                        super.onNext(response);
                        TmpKeyInfo tmpKeyInfo = response.getData();
                        if (StatusCode.SUCCESS != response.getCode()
                                || null == tmpKeyInfo) {
                            Log.e(TAG, "get tmp key failed, code[%d], message[%s]",
                                    response.getCode(), response.getMsg());
                            listener.onFailure(null);
                            return;
                        }
                        TXStorageService.sInstance.upload(tmpKeyInfo, data, filePath, listener);
                    }
                });

    }

    private void upload(TmpKeyInfo tmpKeyInfo, byte[] data, String filePath,
                        final StorageResultListener<TACStorageTaskSnapshot> listener) {

        String bucketName = tmpKeyInfo.getBucketName();
        String region = tmpKeyInfo.getRegion();
        String path = tmpKeyInfo.getPath();

        mMyCredentialProvider.setTmpKeyInfo(tmpKeyInfo);

        TACStorageService storage = TACStorageService.getInstance(bucketName, region);
        TACStorageReference reference = storage.referenceWithPath(path);

        final TACStorageUploadTask uploadTask;
        if (null != data) {
            uploadTask = reference.putData(data, null);
        } else {
            File localFile = new File(filePath);
            uploadTask = reference.putFile(Uri.fromFile(localFile), null);
        }

        uploadTask.addResultListener(new StorageResultListener<TACStorageTaskSnapshot>() {
            @Override
            public void onSuccess(TACStorageTaskSnapshot snapshot) {
                listener.onSuccess(snapshot);
                uploadTask.removeResultListener(this);
            }

            @Override
            public void onFailure(TACStorageTaskSnapshot snapshot) {
                listener.onFailure(snapshot);
                uploadTask.removeResultListener(this);
            }
        });
    }

    private static class MyCredentialProvider implements QCloudCredentialProvider {

        private TmpKeyInfo mTmpKeyInfo;

        public MyCredentialProvider() {
        }

        public MyCredentialProvider(TmpKeyInfo tmpKeyInfo) {
            mTmpKeyInfo = tmpKeyInfo;
        }

        public TmpKeyInfo getTmpKeyInfo() {
            return mTmpKeyInfo;
        }

        public void setTmpKeyInfo(TmpKeyInfo tmpKeyInfo) {
            mTmpKeyInfo = tmpKeyInfo;
        }

        @Override
        public QCloudCredentials getCredentials() throws QCloudClientException {
            if (null == mTmpKeyInfo) {
                return null;
            }
            String secretId = mTmpKeyInfo.getSecretId();
            String secretKey = mTmpKeyInfo.getSecretKey();
            String sessionToken = mTmpKeyInfo.getSessionToken();
            long validTime = mTmpKeyInfo.getValidTime();

            return new SessionQCloudCredentials(secretId, secretKey, sessionToken, validTime);
        }

        @Override
        public void refresh() throws QCloudClientException {

        }
    }
}
